www.gusucode.com > VC++ 三维图形生成和察看工具 > VC++ 三维图形生成和察看工具/code/mesh/Lib3D/Texture.cpp

    //Download by http://www.NewXing.com
//********************************************
// Texture.cpp
//********************************************
// class CTexture
//********************************************
// alliez@usc.edu
// Created : 17/12/97
// Modified : 19/12/97
//********************************************

#include "stdafx.h"
#include "math.h"
#include "Texture.h"

//////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////

//********************************************
// Constructor
//********************************************
CTexture::CTexture()
{
	m_pData = NULL;
	m_Width = 0;
	m_WidthByte32 = 0;
	m_Height = 0;
	m_Depth = 0;
	m_FileName = _T("");
}

//********************************************
// Destructor
//********************************************
CTexture::~CTexture()
{
	Free();
}


//////////////////////////////////////////////
// DATAS
//////////////////////////////////////////////

//********************************************
// Alloc
//********************************************
int CTexture::Alloc(unsigned int width,
										unsigned int height,
										unsigned int depth)
{
	Free();

	unsigned int BytePerPixel = (unsigned int)(depth / 8);
	unsigned int Width32 = WidthByte32(width,depth);

	// Only rgb and rgba modes
	ASSERT(BytePerPixel == 3 || 
		     BytePerPixel == 4);

	m_pData = new unsigned char [Width32 * height];
	if(m_pData == NULL)
		{
		TRACE("CTexture::Alloc : Insuffisant memory\n");
		AfxMessageBox("CTexture::Alloc : Insufisant memory");
		return 0;
		}

	// Set members variables
	m_Width = width;
	m_WidthByte32 = Width32;
	m_Height = height;
	m_Depth = depth;
	UpdateHeader();

	return 1;
}

//********************************************
// Free
//********************************************
void CTexture::Free()
{
	if(m_pData != NULL)
		{
		delete [] m_pData;
		m_pData = NULL;
		}
	m_Width = 0;
	m_Height = 0;
	m_Depth = 0;
}


//////////////////////////////////////////////
//////////////////////////////////////////////
// FILE READING
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// ReadFile
// Redirection
//********************************************
int CTexture::ReadFile(char *filename,
											 unsigned int width,
											 unsigned int height,
											 unsigned int depth)
{
	// Cleanup
	Free();

	// Storage
	m_FileName = filename;

	// Extension
	CString string = filename;
	string.MakeLower();
	TRACE("CTexture::ReadFile : file : %s\n",filename);
	CString extension = string.Right(4);

	// Redirection BMP
	if(extension == ".bmp")
		return ReadFileBMP(filename);


	// Redirection RAW
	if(extension == ".raw")
		return ReadFileRAW(filename,width,height,depth);

	// Unrecognized file format
	CString message;
	message.Format("CTexture::ReadFile : invalid file redirection : %s\n",filename);
	AfxMessageBox(string);

	return 0;
}


//********************************************
// ReadFileBMP (*.bmp)
//********************************************
// Read windows bmp files
// Accept only 24 bits
// Size : 2^n x 2^m
//********************************************
int CTexture::ReadFileBMP(char *filename)
{

	// Check for valid bmp file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename, CFile::modeRead | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for reading");
		return 0;
	}

	// File header
	BITMAPFILEHEADER FileHeader;
	TRY
	{
		file.Read(&FileHeader,sizeof(BITMAPFILEHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading file header");
		file.Close();
		return 0;
	}
	END_CATCH

	TRACE("FileHeader.bfType : %d\n",FileHeader.bfType);
	TRACE("FileHeader.bfSize : %d\n",FileHeader.bfSize);
	TRACE("FileHeader.bfReserved1 : %d\n",FileHeader.bfReserved1);
	TRACE("FileHeader.bfReserved2 : %d\n",FileHeader.bfReserved2);
	TRACE("FileHeader.bfOffBits : %d\n",FileHeader.bfOffBits);

	// Is it a Windows BMP file ? (BM)
  WORD sign = ((WORD) ('M' << 8) | 'B');
	if(FileHeader.bfType != sign)
	{
		AfxMessageBox("Invalid BMP file");
		file.Close();
		return 0;
	}

	// Image header
	TRY
	{
		file.Read(&m_Header,sizeof(BITMAPINFOHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading image header");
		file.Close();
		return 0;
	}
	END_CATCH

	// DEBUG
	TRACE("\n");
	TRACE("IMAGE HEADER :\n");
	TRACE("biSize : %d\n",m_Header.biSize);
	TRACE("biWidth : %d\n",m_Header.biWidth);
	TRACE("biHeight : %d\n",m_Header.biHeight);
	TRACE("biPlanes : %d\n",m_Header.biPlanes);
	TRACE("biBitCount : %d\n",m_Header.biBitCount);
	TRACE("biCompression : %d\n",m_Header.biCompression);
	TRACE("biSizeImage : %d\n",m_Header.biSizeImage);
	TRACE("biXPelsPerMeter : %d\n",m_Header.biXPelsPerMeter);
	TRACE("biYPelsPerMeter : %d\n",m_Header.biYPelsPerMeter);
	TRACE("biClrUsed : %d\n",m_Header.biClrUsed);
	TRACE("biClrImportant : %d\n",m_Header.biClrImportant);

	// 24 bits ?
	if(m_Header.biPlanes != 1 ||
		 m_Header.biBitCount != 24)
	{
		AfxMessageBox("Texture file must have 24 bits depth");
		file.Close();
		return 0;
	}

	// Alloc (does call Free before)
	Free();
	m_pData = new unsigned char[m_Header.biSizeImage];
	if(m_pData == NULL)
	{
		AfxMessageBox("Insuffisant memory");
		file.Close();
		return 0;
	}

	// Update datas
	m_Width = m_Header.biWidth;
	m_Height = m_Header.biHeight;
	m_Depth = m_Header.biBitCount;

	// Image reading
	TRY
	{
		file.Read(m_pData,m_Header.biSizeImage);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	// Success, also set FileName
	m_FileName = filename;

	UpdateWidthByte32();

	return 1;
}

//********************************************
// UpdateWidthByte32
//********************************************
void CTexture::UpdateWidthByte32()
{
	m_WidthByte32 = WidthByte32(m_Width,m_Depth);
}

//********************************************
// WidthByte32
//********************************************
unsigned int CTexture::WidthByte32(unsigned int width,
																	 unsigned int depth)
{
	// 32 bits alignment (4 bytes)
	int rest=(width*depth/8)%4;
	if(rest != 0)
		return (width*depth/8 + 4-rest);
	else
		return (width*depth/8);
}

//********************************************
// UpdateHeader
//********************************************
void CTexture::UpdateHeader()
{
	UpdateWidthByte32();

	m_Header.biWidth = m_Width;
	m_Header.biHeight = m_Height;
	m_Header.biSizeImage = m_WidthByte32 * m_Height;

	m_Header.biSize = 40;
	m_Header.biPlanes = 1;
	m_Header.biBitCount = (unsigned short)m_Depth;
	m_Header.biCompression = 0;
	m_Header.biXPelsPerMeter = 0;
	m_Header.biYPelsPerMeter = 0;
	m_Header.biClrUsed = 0;
	m_Header.biClrImportant = 0;
}


//********************************************
// ReadFileRAW (*.raw)
//********************************************
// Read raw files
// Accept only 24 or 32 bits
// Size : 2^n x 2^m
//********************************************
int CTexture::ReadFileRAW(char *filename,
													unsigned int width,
													unsigned int height,
													unsigned int depth)
{

	ASSERT(width>0);
	ASSERT(height>0);
	ASSERT(depth>0);
	ASSERT(depth%8==0);
	ASSERT(depth/8==3 || depth/8==4);

	// Check for valid file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename, CFile::modeRead | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for reading");
		return 0;
	}

	// Alloc (does call Free before)
	if(!Alloc(width,height,depth))
	{
		AfxMessageBox("Insuffisant memory");
		file.Close();
		return 0;
	}

	// Image reading
	TRY
	{
		file.Read(m_pData,m_Width*m_Height*depth/8);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during reading " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during reading image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	// Success, also set FileName
	m_FileName = filename;

	return 1;
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// FILE SAVING
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// SaveFile
// Redirection
//********************************************
int CTexture::SaveFile(char *filename)
{
	CString string = filename;
	string.MakeLower();
	TRACE("CTexture::SaveFile : file : %s\n",filename);

	CString extension = string.Right(4);

	// Redirection RAW
	if(extension == ".raw")
		return SaveFileRAW(filename);

	// Redirection BMP
	if(extension == ".bmp")
		return SaveFileBMP(filename);

	// Unrecognized file format
	CString message;
	message.Format("CTexture::SaveFile : invalid file redirection : %s\n",filename);
	AfxMessageBox(message);

	return 0;
}


//********************************************
// SaveFileRAW
//********************************************
int CTexture::SaveFileRAW(char *filename)
{
	// Check for valid image
	if((m_Width * m_Height * m_Depth) == 0)
		{
		AfxMessageBox("CTexture::SaveFileRAW : invalid image");
		return 0;
		}

	// Check for valid file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename, CFile::modeWrite | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for writing");
		return 0;
	}

	// Image writing
	TRY
	{
		file.Write(m_pData,m_Width*m_Height*m_Depth/8);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	return 1;
}


//********************************************
// SaveFileBMP (*.bmp)
//********************************************
// Save windows bmp files
// Accept only 24 bits
//********************************************
int CTexture::SaveFileBMP(char *filename)
{
	if(!IsValid())
		return 0;

	if(m_Depth != 24)
		return 0;

	// Check for valid bmp file
	CFile file;
	CFileException ex;
	
	// Try to open file
	if(!file.Open(filename,CFile::modeCreate | CFile::modeWrite | CFile::typeBinary,&ex))
	{
		#ifdef _DEBUG
		  afxDump << "File could not be opened " << ex.m_cause << "\n";
		#endif
		AfxMessageBox("Unable to open file for writing");
		return 0;
	}

	// File header
	BITMAPFILEHEADER FileHeader;
  WORD sign = ((WORD) ('M' << 8) | 'B');
	FileHeader.bfType = sign;
  FileHeader.bfSize = 14 + 40 + m_WidthByte32*m_Height; 
  FileHeader.bfReserved1 = 0; 
  FileHeader.bfReserved2 = 0; 
  FileHeader.bfOffBits = 54; 

	TRACE("\nSave BMP File...\n");
	TRACE("FileHeader.bfType : %d\n",FileHeader.bfType);
	TRACE("FileHeader.bfSize : %d\n",FileHeader.bfSize);
	TRACE("FileHeader.bfReserved1 : %d\n",FileHeader.bfReserved1);
	TRACE("FileHeader.bfReserved2 : %d\n",FileHeader.bfReserved2);
	TRACE("FileHeader.bfOffBits : %d\n",FileHeader.bfOffBits);

	TRY
	{
		file.Write(&FileHeader,sizeof(BITMAPFILEHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing file header");
		file.Close();
		return 0;
	}
	END_CATCH

	// Image header
	TRY
	{
		file.Write(&m_Header,sizeof(BITMAPINFOHEADER));
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing image header");
		file.Close();
		return 0;
	}
	END_CATCH

	// DEBUG
	TRACE("\n");
	TRACE("IMAGE HEADER :\n");
	TRACE("biSize : %d\n",m_Header.biSize);
	TRACE("biWidth : %d\n",m_Header.biWidth);
	TRACE("biHeight : %d\n",m_Header.biHeight);
	TRACE("biPlanes : %d\n",m_Header.biPlanes);
	TRACE("biBitCount : %d\n",m_Header.biBitCount);
	TRACE("biCompression : %d\n",m_Header.biCompression);
	TRACE("biSizeImage : %d\n",m_Header.biSizeImage);
	TRACE("biXPelsPerMeter : %d\n",m_Header.biXPelsPerMeter);
	TRACE("biYPelsPerMeter : %d\n",m_Header.biYPelsPerMeter);
	TRACE("biClrUsed : %d\n",m_Header.biClrUsed);
	TRACE("biClrImportant : %d\n",m_Header.biClrImportant);

	// Image writing
	TRY
	{
		file.Write(m_pData,m_Header.biSizeImage);
	}
	CATCH(CFileException, e)
	{
		#ifdef _DEBUG
				afxDump << "Error during writing " << e->m_cause << "\n";
		#endif
		AfxMessageBox("Error during writing image");
		file.Close();
		return 0;
	}
	END_CATCH

	// Close file
  file.Close();

	return 1;
}




//////////////////////////////////////////////
//////////////////////////////////////////////
// CHECKING
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// IsValid
//********************************************
int CTexture::IsValid()
{
	int success = 0;
	success = (m_Depth == 24) || (m_Depth == 32);
	success &= (m_Width != 0);
	success &= (m_Height != 0);
	success &= (m_pData != NULL);
	if(!success)
		{
		TRACE("\n");
		TRACE("Invalid texture\n");
		TRACE("Width  : %d\n",m_Width);
		TRACE("Height : %d\n",m_Height);
		TRACE("Depth  : %d\n",m_Depth);
		TRACE("Data   : %x\n",m_pData);
		}
	return success;
}


//********************************************
// HigherPowerOfTwo
//********************************************
int CTexture::HigherPowerOfTwo(int value)
{
	ASSERT(value > 0);
	if(value <= 0)
		return value;

	int power = 1;
	int x = 0;

	while(1)
	{
		x = (int)pow(2,power);
		if(x >= value)
			return x;
		power++;
	}

	return value;
}

//********************************************
// LowerPowerOfTwo
//********************************************
int CTexture::LowerPowerOfTwo(int value)
{
	ASSERT(value > 0);
	if(value <= 0)
		return value;

	int power = 1;
	int x = 0;

	while(1)
	{
		x = (int)pow(2,power);
		if(x >= value)
			return (int)pow(2,power-1);
		power++;
	}

	return value;
}

//********************************************
// SameSize
//********************************************
int CTexture::SameSize(CTexture *pTexture)
{
	int success = (m_Width == pTexture->GetWidth());
	success &= (m_Height == pTexture->GetHeight());
	return success;
}


//********************************************
// Flip BGR to RGB
//********************************************
int CTexture::BGRtoRGB(void)
{
	if(!IsValid())
		return 0;

	unsigned char pixel;
	int BytePerPixel = m_Depth/8;
	for(unsigned int j=0;j<m_Height;j++)
		for(unsigned int i=0;i<m_Width;i++)
		{
			pixel = m_pData[m_WidthByte32*j+i*BytePerPixel+2];
			m_pData[m_WidthByte32*j+i*BytePerPixel+2] = m_pData[m_WidthByte32*j+i*BytePerPixel];
			m_pData[m_WidthByte32*j+i*BytePerPixel] = pixel;
		}
	return 1;
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// DUPLICATE
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// Extract
//********************************************
int CTexture::Extract(int left,
											int top,
											int right,
											int bottom)
{
	ASSERT(IsValid());

	// Saturate
	if(right == -1)
		right = m_Width-1;
	if(bottom == -1)
		bottom = m_Height-1;

	// Check
	if(left >= right || top >= bottom)
		return 0;
	if(left < 0  || left >= (int)m_Width || 
		 right < 0 || right >= (int)m_Width)
		return 0;
	if(top < 0  || top >= (int)m_Height || 
		 bottom < 0 || bottom >= (int)m_Height)
		return 0;

	int NewWidth = right-left+1;
	int NewWidthByte32 = WidthByte32(NewWidth,m_Depth);
	int NewHeight = bottom-top+1;
	int BytePerPixel = m_Depth / 8;
	int i,j,k;

	TRACE("Start extracting...\n");
	TRACE("New width : %d\n",NewWidth);
	TRACE("New height : %d\n",NewHeight);

	ASSERT(NewWidth>=1);
	ASSERT(NewHeight>=1);

	// Alloc
	unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
	if(pData == NULL)
		{
		AfxMessageBox("Insuffisant memeory");
		return 0;
		}

	for(j=0;j<NewHeight;j++)
		for(i=0;i<NewWidth;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(m_Height-1-(j+top))+(i+left)*BytePerPixel+k];

	// Replace datas
	delete [] m_pData;
	m_pData = pData;
	m_Width = NewWidth;
	m_WidthByte32 = NewWidthByte32;
	m_Height = NewHeight;

	UpdateHeader();

	return 1;
}


//********************************************
// DuplicateMirror
//********************************************
int CTexture::DuplicateMirror(int left,
															int top,
															int right,
															int bottom)
{

	if(!Extract(left,top,right,bottom))
		return 0;

	left = 0;
	right = m_Width-1;
	top = 0;
	bottom = m_Height-1;

	int NewWidth = 2*m_Width;
	int NewWidthByte32 = WidthByte32(NewWidth,m_Depth);
	int NewHeight = 2*m_Height;
	int BytePerPixel = m_Depth / 8;
	int i,j,k;

	TRACE("Start duplicate mirror...\n");
	TRACE("New width : %d\n",NewWidth);
	TRACE("New widthbyte32 : %d\n",NewWidthByte32);
	TRACE("New height : %d\n",NewHeight);

	ASSERT(NewWidth>=1);
	ASSERT(NewHeight>=1);

	// Alloc
	unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
	if(pData == NULL)
		{
		AfxMessageBox("Insuffisant memeory");
		return 0;
		}

	// o o
	// x o
	for(j=0;j<NewHeight/2;j++)
		for(i=0;i<NewWidth/2;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(i+left)*BytePerPixel+k];
	// o o
	// o x
	for(j=0;j<NewHeight/2;j++)
		for(i=NewWidth/2;i<NewWidth;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(right-(i-NewWidth/2+left))*BytePerPixel+k];
	// x o
	// o o
	for(j=NewHeight/2;j<NewHeight;j++)
		for(i=0;i<NewWidth/2;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(j-NewHeight/2+top)+(i+left)*BytePerPixel+k];
	// o x
	// o o
	for(j=NewHeight/2;j<NewHeight;j++)
		for(i=NewWidth/2;i<NewWidth;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(j-NewHeight/2+top)+(right-(i-NewWidth/2+left))*BytePerPixel+k];

	// Replace datas
	delete [] m_pData;
	m_pData = pData;
	m_Width = NewWidth;
	m_WidthByte32 = NewWidthByte32;
	m_Height = NewHeight;

	UpdateHeader();

	return 1;
}




//********************************************
// DuplicateRepeatWidth
//********************************************
int CTexture::DuplicateRepeatWidth(int left,
																	 int top,
																	 int right,
																	 int bottom)
{
	if(!Extract(left,top,right,bottom))
		return 0;

	left = 0;
	right = m_Width-1;
	top = 0;
	bottom = m_Height-1;

	int NewWidth = 2*m_Width;
	int NewWidthByte32 = WidthByte32(NewWidth,m_Depth);
	int NewHeight = m_Height;
	int BytePerPixel = m_Depth / 8;
	int i,j,k;

	TRACE("Start duplicate mirror...\n");
	TRACE("New width : %d\n",NewWidth);
	TRACE("New widthbyte32 : %d\n",NewWidthByte32);
	TRACE("New height : %d\n",NewHeight);

	ASSERT(NewWidth>=1);
	ASSERT(NewHeight>=1);

	// Alloc
	unsigned char *pData = new unsigned char[NewWidthByte32*NewHeight];
	if(pData == NULL)
		{
		AfxMessageBox("Insuffisant memeory");
		return 0;
		}

	// x o
	for(j=0;j<NewHeight;j++)
		for(i=0;i<NewWidth/2;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(i+left)*BytePerPixel+k];
	// o x
	for(j=0;j<NewHeight;j++)
		for(i=NewWidth/2;i<NewWidth;i++)
			for(k=0;k<BytePerPixel;k++)
				pData[NewWidthByte32*j+i*BytePerPixel+k] = m_pData[m_WidthByte32*(bottom-(j+top))+(i-NewWidth/2+left)*BytePerPixel+k];

	// Replace datas
	delete [] m_pData;
	m_pData = pData;
	m_Width = NewWidth;
	m_WidthByte32 = NewWidthByte32;
	m_Height = NewHeight;

	UpdateHeader();

	return 1;
}





//////////////////////////////////////////////
//////////////////////////////////////////////
// ALPHA
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// SetAlphaLayer
//********************************************
int CTexture::SetAlphaLayer(unsigned char alpha) // 0 - 255
{
	// Check
	if(!IsValid())
		return 0;

	if(m_Depth != 32)
		return 0;

	// Fill alpha layer 
	int size = m_Width * m_Height;
	for(int i=0;i<4*size;i+=4)
		m_pData[i+3] = alpha;

	return 1;
}

//********************************************
// AddAlphaLayer
//********************************************
int CTexture::AddAlphaLayer(unsigned char alpha) // 0 - 255
{
	// Check
	if(!IsValid())
		return 0;

	// Has soon alpha
	if(HasAlpha())
		return SetAlphaLayer(alpha);

	// Alloc memory
	unsigned char *pData = new unsigned char[4*m_Width*m_Height];
	if(pData == NULL)
		{
		AfxMessageBox("CTexture::AddAlphaLayer : insuffisant memory");
		return 0;
		}

	// Fill new data
	int size = m_Width * m_Height;
	int BytePerPixel = m_Depth / 8;
	ASSERT(size > 0);
	for(int i=0;i<size;i++)
	{
		pData[4*i+0] = m_pData[BytePerPixel*i+0];
		pData[4*i+1] = m_pData[BytePerPixel*i+1];
		pData[4*i+2] = m_pData[BytePerPixel*i+2];
		pData[4*i+3] = alpha;
	}

	// Set new depth
	m_Depth = 32;

	// Replace datas
	delete [] m_pData;
	m_pData = pData;

	return 1;
}


//********************************************
// PutAlpha
// From RGB to grey scales, then alpha layer
//********************************************
int CTexture::PutAlpha(CTexture *pTexture) 
{
	// Check
	if(!IsValid())
		return 0;
	if(!pTexture->IsValid())
		return 0;

	if(!SameSize(pTexture))
		return 0;

	if(!AddAlphaLayer(0))
		return 0;

	// Fill new data
	unsigned char *pData = pTexture->GetData();
	int size = m_Width * m_Height;
	int BytePerPixel = pTexture->GetDepth() / 8;
	ASSERT(size > 0);
	for(int i=0;i<size;i++)
		m_pData[4*i+3] = (unsigned char)(((int)pData[BytePerPixel*i+0]+
		                                 (int)pData[BytePerPixel*i+1]+
																		 (int)pData[BytePerPixel*i+2])/3);

	return 1;
}

//////////////////////////////////////////////
//////////////////////////////////////////////
// DISPLAY
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// Draw
//********************************************
int CTexture::Draw(CDC *pDC,
									 int xOffset,
									 int yOffset,
									 int width,
									 int height)
{
	// Checking
	if(!IsValid())
	  return 0;

	// Flags	
	if(width == -1)
		width = m_Width;
	if(height == -1)
		height = m_Height;

	// Painting
	return SetDIBitsToDevice(pDC->m_hDC,
		                       xOffset,
													 yOffset,
													 width,
													 height,
													 0,
													 0,
													 0,
													 m_Height,
													 GetData(),
													 (CONST BITMAPINFO *)&m_Header,
													 DIB_RGB_COLORS);
}

//********************************************
// ReadBuffer
//********************************************
int CTexture::ReadBuffer(unsigned char *buffer, 
												 int width, 
												 int height, 
												 int depth)
{
	if(buffer == NULL)
		return 0;

	if(!Alloc(width,height,depth))
		return 0;

	int BytePerPixel = depth / 8;

	for(int j=0;j<height;j++)
		for(int i=0;i<width;i++)
			for(int k=0;k<BytePerPixel;k++)
			{
				m_pData[m_WidthByte32*j + i*BytePerPixel+k] = 
				  buffer[(width*j+i)*BytePerPixel+k];
				//TRACE("pixel : %d\n",(int)buffer[(width*j+i)*BytePerPixel+k]);
			}

	return 1;
}

//********************************************
// ReadBuffer
//********************************************
int CTexture::ReadBuffer(float *buffer, 
												 int width, 
												 int height, 
												 int depth)
{
	if(buffer == NULL)
		return 0;

	if(!Alloc(width,height,depth))
		return 0;

	int BytePerPixel = depth / 8;

	for(int j=0;j<height;j++)
		for(int i=0;i<width;i++)
			for(int k=0;k<BytePerPixel;k++)
			{
				ASSERT(buffer[(width*j+i)*BytePerPixel+k] <= 1.0f);
				ASSERT(buffer[(width*j+i)*BytePerPixel+k] >= 0.0f);
				m_pData[m_WidthByte32*j + i*BytePerPixel+k] = (BYTE)(255.0f * buffer[(width*j+i)*BytePerPixel+k]);
			}

	return 1;
}

//********************************************
// Grey
//********************************************
int CTexture::Grey(unsigned int x,
									 unsigned int y)
{
	ASSERT(x<m_Width && x>=0);
	ASSERT(y<m_Height && y>=0);
	int BytePerPixel = m_Depth / 8;
	// Grey scale
	if(BytePerPixel == 1)
		return (int)m_pData[m_WidthByte32*y + x]; 
	else // 24 or 32 bits (alpha layer)
		return (int)((int)m_pData[m_WidthByte32*y + x*BytePerPixel+0]+ 
		             (int)m_pData[m_WidthByte32*y + x*BytePerPixel+1]+
								 (int)m_pData[m_WidthByte32*y + x*BytePerPixel+2])/3;
}

//********************************************
// Color
//********************************************
void CTexture::Color(unsigned int x,
 									   unsigned int y, 
										 unsigned char *pRed,
										 unsigned char *pGreen,
										 unsigned char *pBlue)
{
	ASSERT(x<m_Width && x>=0);
	ASSERT(y<m_Height && y>=0);
	int BytePerPixel = m_Depth / 8;
	// Grey scale
	if(BytePerPixel == 1)
	{
		*pRed = m_pData[m_WidthByte32*y + x]; 
		*pGreen = m_pData[m_WidthByte32*y + x]; 
		*pBlue = m_pData[m_WidthByte32*y + x]; 
	}
	else // 24 or 32 bits (alpha layer)
	{
		*pRed = m_pData[m_WidthByte32*y + x*BytePerPixel]; 
		*pGreen = m_pData[m_WidthByte32*y + x*BytePerPixel+1]; 
		*pBlue = m_pData[m_WidthByte32*y + x*BytePerPixel+2]; 
	}
}


HANDLE CTexture::ExportHandle()
{
	HANDLE handle;

	TRACE("Export handle...");
  // Process source handle size
  int size = sizeof(BITMAPINFOHEADER) + m_WidthByte32 * m_Height;
  // Alloc memory
	TRACE("alloc...");
  handle = (HANDLE)::GlobalAlloc (GHND,size);
  if(handle != NULL)
	{
		char *pData = (char *) ::GlobalLock((HGLOBAL)handle);
		TRACE("lock...");
		// Copy header
		TRACE("header...");
		memcpy(pData,&m_Header,sizeof(BITMAPINFOHEADER));
		// Copy datas
		TRACE("datas...");
		memcpy(pData+sizeof(BITMAPINFOHEADER),m_pData,m_WidthByte32*m_Height);
		// Unlock
		TRACE("unlock...");
		::GlobalUnlock((HGLOBAL)handle);
	}
	TRACE("ok\n");
	return handle;
}



// ** EOF **